
/**
 * 构造树型结构数据
 * @param {*} data 数据源
 * @param {*} id id字段 默认 'id'
 * @param {*} parentId 父节点字段 默认 'parentId'
 * @param {*} children 孩子节点字段 默认 'children'
 */
export default {
    handleTree(data, id, parentId, children) {
        let config = {
            id: id || 'id',
            parentId: parentId || 'parentId',
            childrenList: children || 'children'
        };

        var childrenListMap = {};
        var nodeIds = {};
        var tree = [];

        for (let d of data) {
            let parentId = d[config.parentId];
            if (childrenListMap[parentId] == null) {
                childrenListMap[parentId] = [];
            }
            nodeIds[d[config.id]] = d;
            childrenListMap[parentId].push(d);
        }

        for (let d of data) {
            let parentId = d[config.parentId];
            if (nodeIds[parentId] == null) {
                tree.push(d);
            }
        }

        for (let t of tree) {
            adaptToChildrenList(t);
        }

        function adaptToChildrenList(o) {
            if (childrenListMap[o[config.id]] !== null) {
                o[config.childrenList] = childrenListMap[o[config.id]];
            }
            if (o[config.childrenList]) {
                for (let c of o[config.childrenList]) {
                    adaptToChildrenList(c);
                }
            }
        }
        return tree;
    },

    /**
     * 把数组转换成树
     * @param flatArray
     * @param options
     * @returns {*[]}
     */
    convertToTree(flatArray, options = {'idField': 'id', 'parentIdField': 'parentId'}) {

        const tree = [];
        let { idField, parentIdField} = options;
        if (!idField) {
            idField = 'id';
        }
        if (!parentIdField) {
            parentIdField = 'parentId';
        }
        function appendToChildren(target, node) {
            if (!target.children) {
                target.children = [];
            }
            target.children.push(node);
        }

        /**
         * 尝试把节点放入树的子节点中
         * 递归操作
         * @param target
         * @param node
         * @returns {boolean} 是否存在父节点
         */
        function tryAppendToTargetChildren(target, node) {
            if (target[idField] === node[parentIdField]) {
                appendToChildren(target, node);
                return true;
            }
            // 如果在当前层级没找到，去节点的子节点查找
            const children = target.children;
            if (children && children.length) {
                for(const child of target.children) {
                    if (tryAppendToTargetChildren(child, node)) {
                        return true;
                    }
                }
            }
            return false;
        }

        flatArray.forEach(item => {
            // 如果存在父节点
            if (!item[parentIdField]) {
                tree.push(item);
                return;
            }
            let existParent = false;
            for(let i = 0;i<tree.length;) {
                const node = tree[i];
                if(tryAppendToTargetChildren(node, item)) {
                    existParent = true;
                }
                // 如果这个的节点的parentId就是当前节点
                // 从tree中移除，这时tree数组少了一个不需要i++了
                if (node[parentIdField] === item[idField]) {
                    appendToChildren(item, node);
                    tree.splice(i, 1);
                } else {
                    i++;
                }
            }
            // 如果在tree里面没有找到父节点，这个节点可以是根节点，加入到tree数组
            if (!existParent) {
                tree.push(item);
            }

        });

        return tree;
    },

    /**
     * 把树转换成数组
     * @param tree
     */
    convertToArray(tree) {
        const res = [];

        function appendToRes(node) {
            const copy = {...node};
            res.push(copy);
            const children = copy.children;
            delete copy.children;
            if (children && children.length) {
                for(const child of children) {
                    appendToRes(child);
                }
            }

        }

        for(const node of tree) {
            appendToRes(node);
        }

        return res;
    }

}